///////////////////////////////////////////////////////////////////////////////////////////////////
// Illusion Ray Development Kit (IDK)           Copyright (c) 2010 ( dimitriy.martynenko@gmail.com )
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2010-05-22
// Updated : ...
// Licence : NEW BSD
// Info	   : IDK Engine
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

namespace Core
{
	class TShaderParameter : public TObject, virtual public IDK::IShaderParameter
	{
		IDKClass;
	private:
		Type::Enum mType;
		uint mID;
		String mName;
		Declaration::Enum mDecl;
		HandlePtr mCustomData;
	public:
		TShaderParameter(Type::Enum typ, Declaration::Enum decl, const String& name, HandlePtr custom = NullPtr) 
			: mType(typ), mID(Invalid), mName(name), mDecl(decl), mCustomData(custom)
		{
		}

		virtual Type::Enum GetType(void)
		{
			return mType;
		} 

		virtual HandlePtr GetCustomData(void)
		{
			return mCustomData;
		}

		virtual uint GetID(void) const
		{
			return mID;
		}

		virtual void SetID(uint id)
		{
			mID = id;
		}

		const String& GetName(void) const
		{
			return mName;
		}

		void SetName(const String &name)
		{
			mName = name;
		}

		virtual Declaration::Enum GetDeclaration(void)
		{
			return mDecl;
		}
	};

	//
	//
	//
	class TShader : public TResource, virtual public IDK::IShader
	{
		IDKClass;
		typedef TResource Base;
	private:
		typedef Array<IDK::ShaderParameter> ShaderParameters;
		ShaderParameters mParameters;
		IDK::Stream mSource[ProgramType::MAX];
		IDK::GPUShader mShaderProgram;
	public:
		TShader(Threading::IThreadEvent& signal, ref<IDK::IStream> stream) : Base(signal, stream, IDK::IResource::NormalPriority), mParameters(new ShaderParameters::Create())
		{
		}

		virtual ~TShader(void)
		{
		}

		virtual void AddParameter(IDK::IShaderParameter::Type::Enum typ, IDK::IShaderParameter::Declaration::Enum decl, const String& name, HandlePtr handleData = NullPtr)
		{
			mParameters->Add(new TShaderParameter(typ, decl, name, handleData));
		}

		virtual ShaderParameters GetParameters(void)
		{
			return mParameters;
		}

		virtual void SetShaderSource(ProgramType::Enum typ, ref<IDK::IStream> stream)
		{
			mSource[typ] = stream;
		}

		virtual IDK::Stream GetShaderSource(ProgramType::Enum typ)
		{
			return mSource[typ];
		}

		virtual void Rendered(IDK::IRenderState& rndState)
		{
			rndState.SetShader(NullPtr);
		}

		virtual bool Render(IDK::IRenderState& rndState)
		{
			if(mShaderProgram == NullPtr || mShaderProgram->IsInvalid())
			{
				mShaderProgram = rndState.CreateShader(mSource[ProgramType::Vertex], mSource[ProgramType::Fragment], mParameters);
			}

			rndState.SetShader(mShaderProgram);
			rndState.SetShaderParameters(mParameters);
			return true;
		}

		virtual bool OnTickLoad(void)
		{
			return true;
		}
	};

	typedef ref<TShader> Shader;
}
